package com.base.engine.graphics;

import com.base.engine.error.EMADErrorCode;
import com.base.engine.error.MADErrorHandler;
import com.base.engine.error.VertexException;
import static org.lwjgl.opengl.GL11.* ; 

public final class MADRenderer {
	
	/* --- Converting coordinates to shapes --- */ 
	public static VertexArray2f toRectangle_2f(float left, float top, float width, float height,
											  float[] u, float[] v, 
											  Color4f color, EDisplayMode displayMode, String name){
		if(color == null || displayMode == null || u.length != 4 || v.length != 4 ||  
			name == null || name.equals(""))
			VertexException.NullPointerException() ; 
		else{
			VertexArray2f tmpArray = new VertexArray2f(4, name, displayMode);
			Vertex2fuv[] tmp1 = new Vertex2fuv[4]; 
			tmp1[0] = new Vertex2fuv(left,top,u[0],v[0]) ; 
			tmp1[1] = new Vertex2fuv(left,top+height,u[1],v[1]);
			tmp1[2] = new Vertex2fuv(left+width, top+height, u[2], v[2]);
			tmp1[3] = new Vertex2fuv(left+width, top, u[3], v[3]);
			for(int i=0; i<4; i++)
				tmpArray.addVertex(new VertexData2fuv(tmp1[i], color)); 
			return tmpArray ; 
		}
		return null ; 
	}

	public static VertexArray2f toSquare_2f(float left, float top, float size, 
											  float[] u, float[]v, 
											  Color4f color, EDisplayMode displayMode, String name){
		return toRectangle_2f(left,top,size,size,u,v,color,displayMode,name);
	}
	
	public static VertexArray3f toRectangle_3f(Vertex3fuv[] vertices, Color4f color,
												EDisplayMode displayMode, String name) {
		if (color == null || displayMode == null || 
				vertices.length != 4 ||   name == null || name.equals(""))
			VertexException.NullPointerException();
		else {
			VertexArray3f tmpArray = new VertexArray3f(4, name, displayMode);
			Vertex3fuv[] tmp1 = new Vertex3fuv[4];
			for (int i = 0; i < 4; i++){
				tmp1[i] = new Vertex3fuv(vertices[i].getX(), vertices[i].getY(), vertices[i].getZ(), 
										 	vertices[i].getU(), vertices[i].getV());
				tmpArray.addVertex(new VertexData3fuv(tmp1[i], color));
			}
			return tmpArray;
		}
		return null;
	}
	
	public static VertexList3f toCuboid_centered(float x, float y, float z, float width, float height, float depth,
										  float[][] u, float[][] v, 
										  Color4f color, EDisplayMode displayMode, String name){
		try{
			float w = width / 2f ; 
			float h = height / 2f ; 
			float d = depth / 2f ; 
			VertexList3f tmpList = new VertexList3f(); 
			Vertex3fuv[][] tmp = new Vertex3fuv[6][4];
			// front 
			tmp[0][0] = new Vertex3fuv(x-w, y-h, z-d, u[0][0], v[0][0]); 
			tmp[0][1] = new Vertex3fuv(x+w, y-h, z-d, u[0][1], v[1][1]) ;
			tmp[0][2] = new Vertex3fuv(x+w, y+h, z-d, u[0][2], v[2][2]) ; 
			tmp[0][3] = new Vertex3fuv(x-w, y+h, z-d, u[0][3], v[3][3]) ; 
			// back 
			tmp[1][0] = new Vertex3fuv(x-w, y-h, z+d, u[1][0], v[1][0]); 
			tmp[1][1] = new Vertex3fuv(x-w, y+h, z+d, u[1][1], v[1][1]); 
			tmp[1][2] = new Vertex3fuv(x+w, y+h, z+d, u[1][2], v[1][2]) ; 
			tmp[1][3] = new Vertex3fuv(x+w, y-h, z+d, u[1][3], v[1][3]) ; 
			// left side
			tmp[2][0] = new Vertex3fuv(x-w, y-h, z+d, u[2][0], v[2][0]);
			tmp[2][1] = new Vertex3fuv(x-w, y-h, z-d, u[2][1], v[2][1]); 
			tmp[2][2] = new Vertex3fuv(x-w, y+h, z-d, u[2][2], v[2][2]); 
			tmp[2][3] = new Vertex3fuv(x-w, y+h, z+d, u[2][3], v[2][3]); 
			// right side
			tmp[3][0] = new Vertex3fuv(x+w, y-h, z-d, u[3][0], v[3][0]); 
			tmp[3][1] = new Vertex3fuv(x+w, y-h, z+d, u[3][1], v[3][1]); 
			tmp[3][2] = new Vertex3fuv(x+w, y+h, z+d, u[3][2], v[3][2]); 
			tmp[3][3] = new Vertex3fuv(x+w, y+h, z-d, u[3][3], v[3][3]); 
			// top 
			tmp[4][0] = new Vertex3fuv(x-w, y+h, z-d, u[4][0], v[4][0]) ; 
			tmp[4][1] = new Vertex3fuv(x+w, y+h, z-d, u[4][1], v[4][1]); 
			tmp[4][2] = new Vertex3fuv(x+w, y+h, z+d, u[4][2], v[4][2]); 
			tmp[4][3] = new Vertex3fuv(x-w, y+h, z+d, u[4][3], v[4][3]); 
			// bottom 
			tmp[5][0] = new Vertex3fuv(x-w, y-h, z-d, u[5][0], v[5][0]); 
			tmp[5][1] = new Vertex3fuv(x-w, y-h, z+d, u[5][1], v[5][1]); 
			tmp[5][2] = new Vertex3fuv(x+w, y-h, z+d, u[5][2], v[5][2]); 
			tmp[5][3] = new Vertex3fuv(x+w, y-h, z-d, u[5][3], v[5][3]); 
			
			// adding to temp. list
			for(int i=0; i<tmp.length; i++)
				tmpList.addSingleVertexArray(toRectangle_3f(tmp[i], color, displayMode, name)); 			
			
			return tmpList ; 
		}catch(Exception e){
			MADErrorHandler.throwException(EMADErrorCode.CREATING_SHAPE, e);
		}
		return null ; 
	}
	
	public static VertexList3f toCube_centered(float x, float y, float z, float size, 
												float[][] u, float[][] v, 
												Color4f color, EDisplayMode displayMode, String name){
		return toCuboid_centered(x,y,z,size,size,size,u,v,color,displayMode,name);
	}
	
	
	/* --- Rendering basic shapes --- */ 
	/* --> Rectangles 2D / 3D 		  */ 
	
	public static void renderRectangle_2f(VertexData2fuv[] vertices, EDisplayMode displayMode, int render_mode){
		if (vertices == null || vertices.length != 4)
			VertexException.NullPointerException();
		else {
			glEnable(GL_BLEND);
			try {
				if (displayMode == EDisplayMode.DM_COLORED)
					glDisable(GL_TEXTURE_2D);
				else if (displayMode == EDisplayMode.DM_TEXTURED) {
					glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
					glEnable(GL_TEXTURE_2D);
				}
				glBegin(render_mode);
				for (VertexData2fuv v : vertices) {
					if (displayMode == EDisplayMode.DM_COLORED)
						glColor4f(v.getColor().getRed(), v.getColor()
								.getGreen(), v.getColor().getBlue(), v
								.getColor().getAlpha());
					else if (displayMode == EDisplayMode.DM_TEXTURED)
						glTexCoord2f(v.getVertex().getU(), v.getVertex().getV());
					glVertex2f(v.getVertex().getX(), v.getVertex().getY());
				}
				glEnd();
				glEnable(GL_TEXTURE_2D);
			} catch (Exception e) {
				MADErrorHandler.throwException(EMADErrorCode.RENDERING_RECTANGLE, e);
			}
			glDisable(GL_BLEND);
		}
	}

	public static void renderRectangle_2f(VertexArray2f vertices, int render_mode){
		if(vertices == null || vertices.getSize() != 4) 
			VertexException.NullPointerException(); 
		else{
			VertexData2fuv[] tmp = vertices.getVertices() ; 
			renderRectangle_2f(tmp, vertices.getDisplayMode(), render_mode);
		}
	}
	
	public static void renderRectangle_3f(VertexData3fuv[] vertices, EDisplayMode displayMode, int render_mode){
		if (vertices == null || vertices.length != 4)
			VertexException.NullPointerException();
		else {
			glEnable(GL_BLEND);
			try {
				if (displayMode == EDisplayMode.DM_COLORED)
					glDisable(GL_TEXTURE_2D);
				else if (displayMode == EDisplayMode.DM_TEXTURED) {
					glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
					glEnable(GL_TEXTURE_2D);
				}
				glBegin(render_mode);
				for (VertexData3fuv v : vertices) {
					if (displayMode == EDisplayMode.DM_COLORED)
						glColor4f(v.getColor().getRed(), v.getColor()
								.getGreen(), v.getColor().getBlue(), v
								.getColor().getAlpha());
					else if (displayMode == EDisplayMode.DM_TEXTURED)
						glTexCoord2f(v.getVertex().getU(), v.getVertex().getV());
					glVertex2f(v.getVertex().getX(), v.getVertex().getY());
				}
				glEnd();
				glEnable(GL_TEXTURE_2D);
			} catch (Exception e) {
				MADErrorHandler.throwException(EMADErrorCode.RENDERING_RECTANGLE, e);
			}
			glDisable(GL_BLEND);
		}	
	}

	public static void renderRectangle_3f(VertexArray3f vertices, int render_mode) {
		if (vertices == null || vertices.getSize() != 4)
			VertexException.NullPointerException();
		else {
			VertexData3fuv[] tmp = vertices.getVertices();
			renderRectangle_3f(tmp, vertices.getDisplayMode(), render_mode);
		}
	}
	

	public static void renderRectangle_2f(VertexData2fuv[] vertices, EDisplayMode displayMode, Color4f color, int render_mode){
		if (vertices == null || vertices.length != 4)
			VertexException.NullPointerException();
		else {
			glEnable(GL_BLEND);
			try {
				if (displayMode == EDisplayMode.DM_COLORED){
					glDisable(GL_TEXTURE_2D);
					glColor4f(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
				}
				else if (displayMode == EDisplayMode.DM_TEXTURED) {
					glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
					glEnable(GL_TEXTURE_2D);
				}
				glBegin(render_mode);
				for (VertexData2fuv v : vertices) {
					if (displayMode == EDisplayMode.DM_TEXTURED)
						glTexCoord2f(v.getVertex().getU(), v.getVertex().getV());
					glVertex2f(v.getVertex().getX(), v.getVertex().getY());
				}
				glEnd();
				glEnable(GL_TEXTURE_2D);
			} catch (Exception e) {
				MADErrorHandler.throwException(EMADErrorCode.RENDERING_RECTANGLE, e);
			}
			glDisable(GL_BLEND);
		}
	}

	public static void renderRectangle_2f(VertexArray2f vertices, Color4f color, int render_mode){
		if(vertices == null || vertices.getSize() != 4) 
			VertexException.NullPointerException(); 
		else{
			VertexData2fuv[] tmp = vertices.getVertices() ; 
			renderRectangle_2f(tmp, vertices.getDisplayMode(), color, render_mode);
		}
	}
	
	public static void renderRectangle_3f(VertexData3fuv[] vertices, EDisplayMode displayMode, Color4f color, int render_mode){
		if (vertices == null || vertices.length != 4)
			VertexException.NullPointerException();
		else {
			glEnable(GL_BLEND);
			try {
				if (displayMode == EDisplayMode.DM_COLORED){
					glDisable(GL_TEXTURE_2D);
					glColor4f(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
				}
				else if (displayMode == EDisplayMode.DM_TEXTURED) {
					glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
					glEnable(GL_TEXTURE_2D);
				}
				glBegin(render_mode);
				for (VertexData3fuv v : vertices) {
					if (displayMode == EDisplayMode.DM_TEXTURED)
						glTexCoord2f(v.getVertex().getU(), v.getVertex().getV());
//					glNormal3f(0,1,1);
					glVertex3f(v.getVertex().getX(), v.getVertex().getY(), v.getVertex().getZ());
				}
				glEnd();
				glEnable(GL_TEXTURE_2D);
			} catch (Exception e) {
				MADErrorHandler.throwException(EMADErrorCode.RENDERING_RECTANGLE, e);
			}
			glDisable(GL_BLEND);
		}	
	}

	public static void renderRectangle_3f(VertexArray3f vertices, Color4f color, int render_mode) {
		if (vertices == null || vertices.getSize() != 4)
			VertexException.NullPointerException();
		else {
			VertexData3fuv[] tmp = vertices.getVertices();
			renderRectangle_3f(tmp, vertices.getDisplayMode(), color, render_mode);
		}
	}
	
	

	
	public static void renderCuboid(VertexList3f vertices, int render_mode){
		if(vertices == null || vertices.getSize() != 6)
			VertexException.NullPointerException();
		else{
			for(VertexArray3f v: vertices.getAll()){
				renderRectangle_3f(v, render_mode);
			}
		}
	}
	
	public static void renderCube(VertexList3f vertices, int render_mode){
		renderCuboid(vertices, render_mode);
	}


	
	public static void renderCuboid(VertexList3f vertices, Color4f color, int render_mode){
		if(vertices == null || vertices.getSize() != 6)
			VertexException.NullPointerException();
		else{
			for(VertexArray3f v: vertices.getAll())
				renderRectangle_3f(v, color, render_mode);
		}
	}
	
	public static void renderCube(VertexList3f vertices, Color4f color, int render_mode){
		renderCuboid(vertices, color, render_mode);
	}
}
